#!/usr/bin/env python3
"""
定时任务管理器
用于管理数据库备份和邮件发送的定时任务
"""
import os
import threading
import time
from datetime import datetime
from typing import Optional, Dict

# 尝试导入schedule模块，如果失败则设置为None
try:
    import schedule
except ImportError:
    schedule = None
    print("警告: 未找到schedule模块，定时任务功能将不可用")

# 导入数据库工具函数
from .db_tools import backup_database
from .email_tools import send_database_backup_email


class BackupScheduler:
    """
    数据库备份定时任务调度器
    """
    
    def __init__(self):
        self.scheduler_thread = None
        self.running = False
        self.config = None
        self.db_path = None
    
    def load_config(self, config: Dict, db_path: str):
        """
        加载配置并更新备份任务
        
        Args:
            config: 应用配置字典
            db_path: 数据库文件路径
        """
        self.config = config
        self.db_path = db_path
        
        # 立即更新任务
        if schedule is not None:
            self._update_tasks()
            print("调度器配置已更新")
    
    def start(self):
        """
        启动定时任务调度器
        """
        if self.running:
            print("定时任务调度器已经在运行中")
            return
        
        if schedule is None:
            print("警告: schedule模块不可用，无法启动定时任务调度器")
            return
        
        self.running = True
        # 使用非daemon线程，确保即使主应用退出，调度器也能完成当前任务
        self.scheduler_thread = threading.Thread(target=self._run_scheduler, daemon=False)
        self.scheduler_thread.start()
        print("定时任务调度器已启动")
    
    def stop(self):
        """
        停止定时任务调度器
        """
        self.running = False
        if self.scheduler_thread:
            self.scheduler_thread.join(timeout=5)
        print("定时任务调度器已停止")
    
    def _run_scheduler(self):
        """
        运行调度器的主循环
        """
        if schedule is None:
            return
            
        print(f"[{datetime.now()}] 定时任务调度器线程已启动，线程ID: {threading.get_ident()}")
            
        # 初始更新一次任务
        self._update_tasks()
        
        while self.running:
            try:
                # 运行所有待执行的任务
                schedule.run_pending()
            except Exception as e:
                print(f"[{datetime.now()}] 运行任务时出错: {str(e)}")
                import traceback
                traceback.print_exc()
            
            # 每秒检查一次
            time.sleep(1)
    
    def _update_tasks(self):
        """
        根据配置更新定时任务
        """
        if schedule is None:
            return
            
        if not self.config or not self.db_path:
            return
        
        # 获取备份配置
        backup_config = self.config.get('backup', {})
        
        # 清除现有的备份任务
        schedule.clear('database_backup')
        
        # 检查是否启用了自动备份
        if backup_config.get('enabled', False):
            # 获取备份频率和时间
            frequency = backup_config.get('frequency', 'daily')  # 'daily' 或 'weekly'
            backup_time = backup_config.get('time', '00:00')    # 格式: HH:MM
            send_email = backup_config.get('send_email', False)  # 是否发送邮件
            
            # 解析备份时间
            try:
                hour, minute = map(int, backup_time.split(':'))
            except ValueError:
                print(f"无效的备份时间格式: {backup_time}，使用默认时间 00:00")
                hour, minute = 0, 0
            
            # 根据频率设置任务
            if frequency == 'daily':
                schedule.every().day.at(f"{hour:02d}:{minute:02d}").do(
                    self._perform_backup, send_email=send_email
                ).tag('database_backup')
                print(f"已设置每日备份任务，时间: {hour:02d}:{minute:02d}")
            elif frequency == 'weekly':
                # 获取星期几，默认为星期日(0)
                weekday = backup_config.get('weekday', 0)
                try:
                    weekday = int(weekday)
                    if weekday < 0 or weekday > 6:
                        raise ValueError
                except ValueError:
                    print(f"无效的星期几: {weekday}，使用默认值 0 (星期日)")
                    weekday = 0
                
                # 设置每周任务
                weekdays = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
                getattr(schedule.every(), weekdays[weekday]).at(f"{hour:02d}:{minute:02d}").do(
                    self._perform_backup, send_email=send_email
                ).tag('database_backup')
                print(f"已设置每周备份任务，星期: {weekdays[weekday]}，时间: {hour:02d}:{minute:02d}")
    
    def _perform_backup(self, send_email: bool = False):
        """
        执行数据库备份
        
        Args:
            send_email: 是否发送邮件
        """
        print(f"[{datetime.now()}] 开始执行自动备份任务")
        print(f"当前工作目录: {os.getcwd()}")
        
        if not self.db_path:
            print("错误: 数据库路径未设置")
            return
        
        # 确保数据库路径是绝对路径
        if not os.path.isabs(self.db_path):
            # 在Docker中可能需要调整路径
            app_root = os.path.dirname(os.path.abspath(__file__))
            self.db_path = os.path.join(app_root, "..", "..", self.db_path)
            print(f"转换为绝对路径: {self.db_path}")
        
        print(f"数据库路径: {self.db_path}")
        print(f"数据库文件是否存在: {os.path.exists(self.db_path)}")
        
        try:
            # 执行备份
            success, backup_file_path = backup_database(self.db_path)
            
            if success:
                print(f"备份成功: {backup_file_path}")
                
                # 验证备份文件是否存在
                if not os.path.exists(backup_file_path):
                    print(f"警告: 备份文件不存在: {backup_file_path}")
                    return
                    
                # 如果配置了发送邮件且备份成功
                if send_email and self.config:
                    print("准备发送备份邮件")
                    email_success, email_message = send_database_backup_email(self.config, backup_file_path)
                    if email_success:
                        print(f"邮件发送成功: {email_message}")
                    else:
                        print(f"邮件发送失败: {email_message}")
            else:
                print(f"备份失败: {backup_file_path}")
                
        except Exception as e:
            print(f"执行备份任务时发生错误: {str(e)}")
            import traceback
            traceback.print_exc()  # 打印完整的异常堆栈
    

        
    def trigger_backup(self, send_email: bool = False) -> tuple[bool, str]:
        """
        手动触发备份任务
        
        Args:
            send_email: 是否发送邮件
        
        Returns:
            tuple[bool, str]: (成功状态, 消息)
        """
        if not self.db_path:
            return False, "数据库路径未设置"
        
        try:
            # 执行备份
            success, backup_file_path = backup_database(self.db_path)
            
            if success:
                # 验证备份文件是否存在
                if not os.path.exists(backup_file_path):
                    return False, f"备份文件不存在: {backup_file_path}"
                    
                # 如果需要发送邮件
                if send_email and self.config:
                    email_success, email_message = send_database_backup_email(self.config, backup_file_path)
                    if email_success:
                        return True, f"备份成功并已发送邮件: {backup_file_path}"
                    else:
                        return False, f"备份成功但邮件发送失败: {email_message}"
                return True, backup_file_path
            else:
                return False, backup_file_path
                
        except Exception as e:
            return False, f"执行备份时发生错误: {str(e)}"


# 创建全局调度器实例
scheduler = BackupScheduler()


def init_scheduler(config: Dict, db_path: str):
    """
    初始化并启动调度器
    
    Args:
        config: 应用配置字典
        db_path: 数据库文件路径
    """
    scheduler.load_config(config, db_path)
    scheduler.start()


def shutdown_scheduler():
    """
    关闭调度器
    """
    scheduler.stop()


def get_scheduler():
    """
    获取调度器实例
    
    Returns:
        BackupScheduler: 调度器实例
    """
    return scheduler